package com.gopay.checkorder.service.impl.bcdl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;

import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.gopay.checkorder.dao.BankBcdlOrderDAO;
import com.gopay.common.Result;
import com.gopay.common.constants.bank.BisBankBusinessProd;
import com.gopay.common.constants.bank.BisBankInterfaceChannel;
import com.gopay.common.constants.bank.IcbcConstants;
import com.gopay.common.constants.proccode.ProcCodeConstants;
import com.gopay.common.domain.bank.BankOrder;
import com.gopay.common.domain.bank.BaseMessage;
import com.gopay.common.domain.bank.BcdlMessage;
import com.gopay.common.domain.bank.BcdlQueryBalance;
import com.gopay.common.domain.bank.BcdlResult;
import com.gopay.common.domain.bank.bcdl.BcdlPacket;
import com.gopay.common.domain.bank.bcdl.BcdlPacketRes;
import com.gopay.common.domain.bank.dayend.BaseDayendEntry;
import com.gopay.common.domain.bank.icbc.bcdl.pay.IcbcMessageData;
import com.gopay.common.domain.bis.BisBankBcdlOrder;
import com.gopay.common.domain.cashier.BankCardType;
import com.gopay.common.domain.cps.CpsGenMainOrder;
import com.gopay.common.domain.cps.vo.CheckOrderResult;
import com.gopay.common.domain.cps.vo.InAccInfo;
import com.gopay.common.exception.GopayException;
import com.gopay.remote.bank.BcdlInteractRemoteService;

/**
 * 
 * 
 * @CheckBcdlOrderIcbcImpl.java
 * @author liujy
 * @2013-3-20 上午11:12:29 www.gopay.com.cn Inc.All rights reserved.
 */
public class CheckBcdlOrderIcbcImpl  extends BaseBcdlOrderProcessImpl{
	private final static Logger logger = LoggerFactory
			.getLogger("ICBC");

	@Resource(name = "bankBcdlClient")
	private BcdlInteractRemoteService bankBcdlClient;
	@Resource(name = "bankBcdlOrderDAO")
	private BankBcdlOrderDAO bankBcdlOrderDAO;

	public BcdlPacketRes query4batch(String packetNo,String label, String bank) {
		BcdlPacketRes result = new BcdlPacketRes();
		try {
			BcdlPacket bcdlPacket = new BcdlPacket();
			bcdlPacket.setPacketNo(packetNo);
			bcdlPacket.setLabel(label);
			bcdlPacket.setBank(bank);
			logger.info("icbc bcdl batch send bank packetNo: " + packetNo);
			result = bankBcdlClient.queryPacket(bcdlPacket);
			logger.info("icbc bcdl batch send bank result: " + ToStringBuilder.reflectionToString(result));
			return result;
		} catch (Exception e) {
			logger.error("银企直连订单对账失败,packetNo: " + packetNo, e);
			result.setResultCode(ProcCodeConstants.PROC_CODE_100E6066);
			return result;
		}
	}
	public BcdlResult send4batch(List<BankOrder> bankOrders, String packetNo,String label,String bank) {
		BcdlResult result = new BcdlResult();
		BcdlPacket bcdlPacket = new BcdlPacket();
		List<BcdlMessage> bcdlMessages= new ArrayList<BcdlMessage>();

		for(BankOrder bankOrder:bankOrders){
			try {
				bcdlMessages.add( buildMsg(bankOrder));
			} catch (Exception e) {
				logger.error("银企直连buildMsg失败,orderId: " + bankOrder.getOrderId(), e);
			}
		}

		try {
			if (null == bcdlMessages || bcdlMessages.size() <= 0) {
				logger.error("包package中无可执行订单，packetNo:"+packetNo);
				throw new Exception("无可执行订单");
			}
			bcdlPacket.setBcdlMessages(bcdlMessages);
			bcdlPacket.setPacketNo(packetNo);
			bcdlPacket.setLabel(label);
			bcdlPacket.setBank(bank);
			logger.info("icbc bcdl batch send bank packetNo: " + packetNo);
			result = bankBcdlClient.sendBankPacket(bcdlPacket);
			return result;
		} catch (Exception e) {
			logger.error("银企直连订单支付失败,packetNo: " + packetNo, e);
			result.setResultCode(ProcCodeConstants.PROC_CODE_100E6066);
			return result;
		}
	}
	
	public BcdlResult sendBank(BankOrder bankOrder, String label) {
		BcdlResult result = new BcdlResult();
		try {
			BcdlMessage base = buildMsg(bankOrder);
			base.setLabel(label);
			logger.info("icbc bcdl send bank orderId: " + bankOrder.getOrderId());
			result = bankBcdlClient.sendBank(base);
			return result;
		} catch (Exception e) {
			logger.error("银企直连订单支付失败: " + bankOrder.getOrderId(), e);
			result.setResultCode(ProcCodeConstants.PROC_CODE_100E6066);
			return result;
		}
	}
	
	public BcdlResult sendBank(BankOrder bankOrder){
		BcdlResult result = new BcdlResult();
		try {
			BcdlMessage base = buildMsg(bankOrder);
			logger.info("icbc bcdl send bank orderId: " + bankOrder.getOrderId());
			result = bankBcdlClient.sendBank(base);
			return result;
		} catch (Exception e) {
			logger.error("银企直连订单支付失败: " + bankOrder.getOrderId(), e);
			result.setResultCode(ProcCodeConstants.PROC_CODE_100E6066);
			return result;
		}
	}
	
    public BcdlResult queryBalance(BcdlQueryBalance queryOrder) {
        BcdlResult result = new BcdlResult();
        try {
            BcdlMessage base = buildQryBalanceMsg(queryOrder);
            logger.info("icbc bcdl query balance send bank orderId: " + queryOrder.getQueryOrderId());
            result = bankBcdlClient.sendBankQueryBalance(base);
            return result;
        } catch (Exception e) {
            logger.error("银企直连订单查询余额失败: " + queryOrder.getQueryOrderId(), e);
            result.setResultCode(ProcCodeConstants.PROC_CODE_100E6027);
            return result;
        }
    }
    
    public BcdlResult queryAcctDetail(Object object) {
        BcdlResult result = new BcdlResult();
        try {
            BcdlMessage base = (BcdlMessage) object;
            result = bankBcdlClient.queryAcctDetail(base);
            return result;
        } catch (Exception e) {
            logger.error("银企直连查询网银明细失败: ", e);
            result.setResultCode(ProcCodeConstants.PROC_CODE_100E6049);
            return result;
        }
    }

	public BcdlMessage buildMsg(BankOrder bankOrder) throws GopayException {
		BcdlMessage bcdlMsg = new BcdlMessage();
		BisBankBcdlOrder bcdl = bankBcdlOrderDAO
				.findBankBcdlOrderById(bankOrder.getOrderId());
		ToStringBuilder.reflectionToString(bcdl);
		bcdlMsg.setBankBusProd(BisBankBusinessProd._09);
		bcdlMsg.setBank(bankOrder.getBankCode());
		bcdlMsg.setBankIntrChann(BisBankInterfaceChannel._00);
		bcdlMsg.setGopayBankOrderNo(bankOrder.getOrderId());
		bcdlMsg.setOrderId(bankOrder.getOrderId());
		bcdlMsg.setOutOrderId(bankOrder.getOutOrderId());

		bcdlMsg.setPobcBankCode(bcdl.getRecvPbocBankCode());// 央行代码
		bcdlMsg.setPbocBankName(bcdl.getRecvBankName());// 央行名称
		bcdlMsg.setPbocBankBranchCode(bcdl.getRecvBankPbocNum());// 联行号
		bcdlMsg.setPbocBankBranchName(bcdl.getRecvBankBranchName());// 联行名
		bcdlMsg.setRecvBankAcctNum(bcdl.getRecvBankAcctNum());// 账号
		bcdlMsg.setRecvBankAcctName(bcdl.getRecvBankAcctName());// 户名
		bcdlMsg.setRecvBankProvNo(bcdl.getRecvBankProvinceCode());// 省代码
		bcdlMsg.setRecvBankProvName(bcdl.getRecvBankProvinceName());// 省名称
		bcdlMsg.setRecvBankCityCode(bcdl.getRecvBankCityCode());// 城市代码
		bcdlMsg.setRecvBankCityName(bcdl.getRecvBankCityName());// 城市名称
		bcdlMsg.setDcblType(bcdl.getBcFlag());
		bcdlMsg.setSysIOFlg(bcdl.getCrossBank());
		bcdlMsg.setEmergency(bcdl.getUrgent());
		int sameCity = 0;
		if (StringUtils.equals(bcdlMsg.getRecvBankProvNo(), "01")
				|| (bcdlMsg.getRecvBankProvName() != null && bcdlMsg
						.getRecvBankProvName().indexOf("北京") != -1)) {
			logger.info("bcdl sameCity: 1"+"==================");
			sameCity = 1;
		}
		bcdlMsg.setIsSameCity(sameCity);
		CpsGenMainOrder mainOrder = getMainOrder(bankOrder.getOrderId());
		if(mainOrder.getSettleAmt()==null){
			throw new RuntimeException("bcdl结算金额为null");
		}
		bcdlMsg.setAmount(mainOrder.getSettleAmt());
		return bcdlMsg;
	}
	
	public BcdlMessage buildQryBalanceMsg(BcdlQueryBalance qryOrder) {
	    BcdlMessage bcdlMsg = new BcdlMessage();
	    bcdlMsg.setBank(qryOrder.getQueryBankCode());
	    bcdlMsg.setOrderId(qryOrder.getQueryOrderId());
	    return bcdlMsg;
	}
	
	@Override
	public CheckOrderResult checkOrder(BankOrder bankOrder, String target) {
		CheckOrderResult checkOrderResult = new CheckOrderResult();
		try {
			checkOrderResult.setSuccess(false);
			checkOrderResult.setOrderId(bankOrder.getOrderId());

			BcdlMessage base = new BcdlMessage();
			base.setBankOrderId(bankOrder.getOrderId());
			base.setOrderId(bankOrder.getOrderId());// 使用订单号
			base.setOutOrderId(bankOrder.getOutOrderId());// 使用外部订单号
			base.setBank(bankOrder.getBankCode());

			BcdlResult result = new BcdlResult();

			logger.error("bcdl check order BcdlMessage: " + ToStringBuilder.reflectionToString(base,
					ToStringStyle.DEFAULT_STYLE));
			
			BisBankBcdlOrder bcdl = bankBcdlOrderDAO
					.findBankBcdlOrderById(bankOrder.getOrderId());
			if( bcdl!=null && StringUtils.isNotBlank(bcdl.getPacketNo())
					&& 0==bcdl.getReonlinepay()){
				BcdlPacket packet = new BcdlPacket();
				List<BcdlMessage> list = new ArrayList<BcdlMessage>();
				list.add(base);
				packet.setBcdlMessages(list);
				packet.setBank(bankOrder.getBankCode());
				packet.setPacketNo(bcdl.getPacketNo());
				
				BcdlPacketRes res = bankBcdlClient.queryPacket(packet);
				List<BcdlResult> resultList = res.getBcdlResults();
				if(null != resultList && resultList.size() > 0){
					result = res.getBcdlResults().get(0);
				}else{
					result.setResultCode(res.getResultCode());
					result.setErrorMsg(res.getResultMsg());
					result.setSuccess(res.isSuccess());
				}
			}else{
				result = bankBcdlClient.query(base);
			}

			logger.error("bcdl check order result: " + result);

			//modified by zyt,2017-10-10, 将result为空和PROC_CODE_100S1000的情况分开写，解决之前null中依然get的潜在空指针
			if (result == null) {
				logger.error("bankBcdlClient fail. result is null");
				return checkOrderResult;
			} else if (!ProcCodeConstants.PROC_CODE_100S1000.equals(result.getResultCode())){
				logger.error("bankBcdlClient fail.");
				logger.error(ToStringBuilder.reflectionToString(result,
						ToStringStyle.DEFAULT_STYLE));

				checkOrderResult.setErrCode(result.getResultCode());
				checkOrderResult.setErrMsg(result.getErrorMsg());
				checkOrderResult.setBankRetCode(result.getBankRetCode());
				if(ProcCodeConstants.PROC_CODE_100E6027.equals(result.getResultCode())){
					checkOrderResult.setBankFailure(true);
					if(result.isNeedRefund()){
						checkOrderResult.setNeedRefund(true);
					}
				}
				return checkOrderResult;
			}

			IcbcMessageData res = (IcbcMessageData) result.getDefaultModel();
			if (res == null) {
				// 查询订单为空
				logger.error("fail:orderId:" + bankOrder.getOrderId()
						+ " errcode:" + ProcCodeConstants.PROC_CODE_100E5062
						+ " err:bis query is null.");
				checkOrderResult
						.setErrCode(ProcCodeConstants.PROC_CODE_100E5062);
				checkOrderResult.setErrMsg("bis query is null.");
				return checkOrderResult;
			}
			if (!result.isSuccess()&&ProcCodeConstants.PROC_CODE_100E6027.equals(result.getResultCode()) ) {
				logger.error("fail:orderId:" + bankOrder.getOrderId()
						+ " errcode:" + ProcCodeConstants.PROC_CODE_100E6027
						+ " err:bis order is fail.");
				checkOrderResult.setBankFailure(true);
				checkOrderResult
						.setErrCode(ProcCodeConstants.PROC_CODE_100E6027);
				checkOrderResult.setErrMsg(result.getErrorMsg());
				checkOrderResult.setBankRetCode(result.getBankRetCode());
			}
			if (IcbcConstants.NCPAYENT_STATUS_BANK_SUCCESS.equals(res
					.getResult())) {

				InAccInfo accInfo = new InAccInfo();
				accInfo.setOrderId(bankOrder.getOrderId());
				accInfo.setAmount(new BigDecimal(res.getPayAmt())
						.movePointLeft(2));
				accInfo.setRetCode("00");
				accInfo.setCardType(BankCardType.Unknown.toString());

				checkOrderResult.setAccInfo(accInfo);
				checkOrderResult.setSuccess(true);
				checkOrderResult
						.setErrCode(ProcCodeConstants.PROC_CODE_100S1000);
			}
			return checkOrderResult;
		} catch (Exception e) {
			e.printStackTrace();
			logger.error("银企直连订单查询失败: " + bankOrder.getOrderId(), e);
			checkOrderResult.setErrCode(ProcCodeConstants.PROC_CODE_100E5062);
			checkOrderResult.setErrMsg("bis is too busy.");
			return checkOrderResult;
		}
	}

	@Override
	public BankOrder getDbOrder() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public BaseMessage dayend(String bank_bus) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Result getDayendMsg(String string) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public List<CheckOrderResult> checkDayend(String bank_bus) {
		// TODO Auto-generated method stub
		return null;
	}




	@Override
	public CheckOrderResult checkDayendOrder(BaseDayendEntry bdm, BankOrder bo) {
		// TODO Auto-generated method stub
		return null;
	}

	public BcdlInteractRemoteService getBankBcdlClient() {
		return bankBcdlClient;
	}

	public void setBankBcdlClient(BcdlInteractRemoteService bankBcdlClient) {
		this.bankBcdlClient = bankBcdlClient;
	}

	public BankBcdlOrderDAO getBankBcdlOrderDAO() {
		return bankBcdlOrderDAO;
	}

	public void setBankBcdlOrderDAO(BankBcdlOrderDAO bankBcdlOrderDAO) {
		this.bankBcdlOrderDAO = bankBcdlOrderDAO;
	}
}
